/*******************************************************************************
 * Copyright (c) 2011 TXT e-solutions SpA
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the research area ICT-2009.1.3
 * Internet of Things and enterprise environments.
 *
 *
 * Authors:
 *     Cristoforo Seccia (TXT e-solutions SpA)
 *
 * Contributors:
 *      Domenico Rotondi (TXT e-solutions SpA)
 *******************************************************************************/
package it.txt.access.capability.wizard.panel.controller;

import it.txt.access.capability.commons.schema.validation.CapabilitySchemaValidationHandler;
import it.txt.access.capability.commons.schema.validation.CapabilitySchemaValidationHandlerException;
import it.txt.access.capability.commons.utils.MessageUtils;
import it.txt.access.capability.commons.utils.XMLPrinter;
import it.txt.access.capability.factory.CapabilitySchemaFactory;
import it.txt.access.capability.factory.CapabilitySchemaFactoryException;
import it.txt.access.capability.schema.AccessRightsCapabilityType;
import it.txt.access.capability.verifier.CapabilityVerifier;
import it.txt.access.capability.verifier.CapabilityVerifierException;
import it.txt.access.capability.verifier.CapabilityVerifierValues;
import it.txt.access.capability.verifier.VerifiedCapability;
import it.txt.access.capability.wizard.Wizard;
import it.txt.access.capability.wizard.WizardPanelController;
import it.txt.access.capability.wizard.panel.PanelAccessType;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.xml.datatype.XMLGregorianCalendar;

import org.w3c.dom.Document;

/**
 *
 * @author Cristoforo Seccia (TXT e-solutions SpA)
 */
public class ControllerPanelAccessType extends WizardPanelController implements ActionListener {

    private static final Logger LOGGER = Logger.getLogger(ControllerPanelAccessType.class.getName());
    private static final Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
    private static final Cursor busyCursor = new Cursor(Cursor.WAIT_CURSOR);
    public static final String ACCESS_CAPABILITY_TYPE = "CAPABILITY";
    public static final String ACCESS_POLICY_TYPE = "POLICY";
    private String recoverAccessRightsCapabilityError = "";
    private boolean isAccessCapabilityTypeProvided = false;
    private boolean isAccessPolicyTypeSelected = true;
    private AccessRightsCapabilityType forwardObject;
    private PanelAccessType panelAccessType;

    public ControllerPanelAccessType(Wizard wizard) {
        super(wizard);
        initComponents();
    }

    private void initComponents() {
        panelAccessType = new PanelAccessType(getWizard(), this);
        panelAccessType.setAccessTypeRadioListener(this);
    }

    @Override
    public Component getPanelComponent() {
        return panelAccessType;
    }

    @Override
    public boolean aboutToDisplayPanel() {
        panelAccessType.validatePanelStatus();
        return true;
    }

    @Override
    public void displayingPanel() {
        boolean forward = isAccessPolicyTypeSelected || isAccessCapabilityTypeProvided;
        getWizard().setBackButtonEnabled(true);
        getWizard().setNextButtonEnabled(forward);
        getWizard().setFinishButtonEnabled(false);
        getWizard().setCancelButtonEnabled(true);
        getWizard().setAccessRightsCreationPercentage(25);
        panelAccessType.validatePanelStatus();
    }

    @Override
    public boolean aboutToHidePanel() {
        if (!isAccessPolicyTypeSelected && isAccessCapabilityTypeProvided) {
            setForwardObject(forwardObject);
            return true;
        }
        return isAccessPolicyTypeSelected || isAccessCapabilityTypeProvided;
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() instanceof JRadioButton) {
            JRadioButton accessTypeRadio = (JRadioButton) e.getSource();
            String accessType = accessTypeRadio.getName();
            isAccessPolicyTypeSelected = accessType.equals(ACCESS_POLICY_TYPE) && accessTypeRadio.isSelected();
            boolean forward = isAccessPolicyTypeSelected || isAccessCapabilityTypeProvided;
            getWizard().setNextButtonEnabled(forward);
        }
    }

    public String getAccessTypeSelected() {
        return isAccessPolicyTypeSelected ? ACCESS_POLICY_TYPE : ACCESS_CAPABILITY_TYPE;
    }

    public boolean recoverAccessRightsCapability(File file) {

        getWizard().setCursor(busyCursor);

        isAccessCapabilityTypeProvided = false;

        String title = "Acquiring Access Rights";

        String message = "Successfully Acquired Access Rights Capability!";

        try {
            AccessRightsCapabilityType capability = 
                    CapabilitySchemaFactory.getInstance().createAccessRights(file);

            CapabilityVerifierValues values = new CapabilityVerifierValues();

            ArrayList<VerifiedCapability> vcs = new ArrayList<VerifiedCapability>();

            if (CapabilityVerifier.accessRightsCapabilityValidityCheck(capability, values, vcs)) {

                LOGGER.log(Level.INFO, "Capability Chain:");
                LOGGER.log(Level.INFO, "************************");
                for (VerifiedCapability verifiedCapability : vcs) {
                    LOGGER.log(Level.INFO, "Capability ID: {0}", verifiedCapability.getCapabilityID());
                    LOGGER.log(Level.INFO, "Capability Issue Date: {0}", verifiedCapability.getIssueDate().toString());
                    LOGGER.log(Level.INFO, "************************");
                }
                if (!values.getInnerAccessRights().isEmpty()) {
                    Document capabilityDoc = CapabilitySchemaFactory.getInstance().createAccessRightsDocument(capability);
                    XMLPrinter.logDocumentElement(capabilityDoc.getDocumentElement(), "Imported Capability (pretty print)", true);
                    isAccessCapabilityTypeProvided = true;
                    forwardObject = capability;                    
                } else {
                    message = "The Capability has no delegable access rights!";
                    recoverAccessRightsCapabilityError = message;
                }
            } else {
                message = "The Capability Validity verifier returned false!";
                recoverAccessRightsCapabilityError = message;
            }
            
            //DEBUG
            //check of the capability integrity
//            LOGGER.log(Level.INFO, "Verifying the signature of the DOM obtained directly from the CAPABILITY file");
//            DocumentBuilderFactory xmlDocBuilderFactory = DocumentBuilderFactory.newInstance();
//            xmlDocBuilderFactory.setNamespaceAware(true);
//            xmlDocBuilderFactory.setIgnoringElementContentWhitespace(true);
//            try {
//                DocumentBuilder xmlDocBuilder = xmlDocBuilderFactory.newDocumentBuilder();
//                Document test = xmlDocBuilder.parse(file);
//                if (X509DocumentSigner.verifyXMLElementSign(test.getDocumentElement())) {
//                    LOGGER.log(Level.INFO, "Signature of file " + file.getAbsolutePath() + " has been VERIFIED!");
//                } else {
//                    LOGGER.log(Level.SEVERE, "Signature of file " + file.getAbsolutePath() + " is NOT VALID!");
//                }
//            } catch (ParserConfigurationException e) {
//                LOGGER.log(Level.SEVERE, "", e);
//            } catch (SAXException e) {
//                LOGGER.log(Level.SEVERE, "", e);
//            } catch (IOException e) {
//                LOGGER.log(Level.SEVERE, "", e);
//            } catch (GeneralSecurityException e) {
//                LOGGER.log(Level.SEVERE, "", e);
//            }
        }
        catch (CapabilitySchemaFactoryException ex) {
            message = ex.getMessage();
            recoverAccessRightsCapabilityError = message;
        } catch (CapabilityVerifierException ex) {
            message = ex.getMessage();
            recoverAccessRightsCapabilityError = message;
        } catch (CapabilitySchemaValidationHandlerException ex) {
            message = ex.getMessage();
            recoverAccessRightsCapabilityError =
                    CapabilitySchemaValidationHandler.dumpValidationEvents(
                    ex.getValidationEvents());
        }

        int type = isAccessCapabilityTypeProvided ? JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE;

        JOptionPane.showMessageDialog(getWizard(), message, title, type);

        getWizard().setNextButtonEnabled(isAccessCapabilityTypeProvided);

        getWizard().setCursor(defaultCursor);

        return isAccessCapabilityTypeProvided;
    }

    public String recoverAccessRightsCapabilityErrorMessage() {
        return MessageUtils.getErrorMessage("Recovering Capability", recoverAccessRightsCapabilityError);
    }

    public String getAccessRightsPublicValuesToString() {
        StringBuilder accessRightsPublicValues = new StringBuilder();
        if (isAccessCapabilityTypeProvided) {
            accessRightsPublicValues.append(MessageUtils.getInfoMessage("Validity Condition Date", null));
            XMLGregorianCalendar notBeforeDate = forwardObject.getValidityCondition().getNotBefore();
            accessRightsPublicValues.append(MessageUtils.getInfoMessage("Not Before", notBeforeDate.toString()));
            XMLGregorianCalendar afterDate = forwardObject.getValidityCondition().getNotOnOrAfter();
            accessRightsPublicValues.append(MessageUtils.getInfoMessage("Not-on-Or After", afterDate.toString()));
            accessRightsPublicValues.append(MessageUtils.getInfoMessage("Issuer", forwardObject.getIssuer().getValue()));
            accessRightsPublicValues.append(MessageUtils.getInfoMessage("Subject ID", forwardObject.getSubject().getSubjectID().getValue()));
            accessRightsPublicValues.append(MessageUtils.getInfoMessage("Resource ID", forwardObject.getResourceID()));
        } else {
            accessRightsPublicValues.append(MessageUtils.getErrorMessage("No Access rights Capability defined.", null));
        }
        return accessRightsPublicValues.toString();
    }
}
